home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Tool Chest / Text / WASTE / WASTE 1.2a2 / WEBirthDeath.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-10-12  |  14.2 KB  |  572 lines  |  [TEXT/CWIE]

  1. /*
  2.  *    WEBirthDeath.c
  3.  *
  4.  *    WASTE PROJECT
  5.  *  Creation and Destruction, Standard Procs, etc.
  6.  *
  7.  *  Copyright (c) 1993-1995 Marco Piovanelli
  8.  *    All Rights Reserved
  9.  *
  10.  *  C port by Dan Crevier
  11.  *
  12.  */
  13.  
  14.  
  15. #include "WASTEIntf.h"
  16.  
  17. #ifndef __PALETTES__
  18. #include <Palettes.h>
  19. #endif
  20.  
  21. #ifndef __QDOFFSCREEN__
  22. #include <QDOffscreen.h>
  23. #endif
  24.  
  25. #ifndef __GESTALT__
  26. #include <Gestalt.h>
  27. #endif
  28.  
  29. #if GENERATINGCFM
  30. #ifndef __CODEFRAGMENTS__
  31. #include <CodeFragments.h>
  32. #endif
  33. #endif
  34.  
  35. // static variables
  36.  
  37. static WEDrawTextUPP        _weStdDrawTextProc = NULL;
  38. static WEPixelToCharUPP        _weStdPixelToCharProc = NULL;
  39. static WECharToPixelUPP        _weStdCharToPixelProc = NULL;
  40. static WELineBreakUPP        _weStdLineBreakProc = NULL;
  41. static WEWordBreakUPP        _weStdWordBreakProc = NULL;
  42. static WECharByteUPP        _weStdCharByteProc = NULL;
  43. static WECharTypeUPP        _weStdCharTypeProc = NULL;
  44.  
  45. pascal void _WEStdDrawText(Ptr pText, long textLength, Fixed slop, 
  46.                 JustStyleCode styleRunPosition, WEHandle hWE)
  47. {
  48. #pragma unused(hWE)
  49.     DrawJustified(pText, textLength, slop, styleRunPosition,
  50.           kOneToOneScaling, kOneToOneScaling);
  51. } // _WEStdDrawText
  52.  
  53. pascal long _WEStdPixelToChar(Ptr pText, long textLength, Fixed slop,
  54.                 Fixed *width, char *edge, JustStyleCode styleRunPosition,
  55.                 Fixed hPos, WEHandle hWE)
  56. {
  57. #pragma unused(hPos, hWE)
  58.     Fixed lastWidth;
  59.     long retVal;
  60.     Boolean theEdge = *edge;
  61.  
  62.     lastWidth = *width;
  63.     retVal = PixelToChar(pText, textLength, slop, lastWidth, &theEdge,
  64.         width, styleRunPosition, kOneToOneScaling, kOneToOneScaling);
  65.     *edge = theEdge;
  66.  
  67.     // round width to nearest integer value
  68.     // (this is supposed to fix an incompatibility with the WorldScript Power Adapter)
  69.     *width = BSL(FixRound(*width), 16);
  70.  
  71.     return retVal;
  72. } // _WEStdPixelToChar
  73.  
  74. pascal short _WEStdCharToPixel(Ptr pText, long textLength, Fixed slop,
  75.                 long offset, short direction, JustStyleCode styleRunPosition,
  76.                 long hPos, WEHandle hWE)
  77. {
  78. #pragma unused(hPos, hWE)
  79.     return CharToPixel(pText, textLength, slop, offset, direction,
  80.             styleRunPosition, kOneToOneScaling, kOneToOneScaling);
  81. } // _WEStdCharToPixel
  82.  
  83. pascal StyledLineBreakCode _WEStdLineBreak(Ptr pText, long textLength,
  84.                 long textStart, long textEnd, Fixed *textWidth,
  85.                 long *textOffset, WEHandle hWE)
  86. {
  87. #pragma unused(hWE)
  88.     return StyledLineBreak(pText, textLength, textStart, textEnd, 0, textWidth,
  89.                 textOffset);
  90. } // _WEStdLineBreak
  91.  
  92. pascal void _WEStdWordBreak(Ptr pText, short textLength, short offset,
  93.                 char edge, OffsetTable breakOffsets, ScriptCode script,
  94.                 WEHandle hWE)
  95. {
  96. #pragma unused(hWE)
  97.     FindWordBreaks(pText, textLength, offset, (Boolean)edge, NULL, breakOffsets,
  98.         script);
  99. } // _WEStdWordBreak
  100.  
  101. pascal short _WEStdCharByte(Ptr pText, short textOffset, ScriptCode script,
  102.                 WEHandle hWE)
  103. {
  104. #pragma unused(hWE)
  105.     return CharacterByteType(pText, textOffset, script);
  106. } // _WEStdCharByte
  107.  
  108. pascal short _WEStdCharType(Ptr pText, short textOffset, ScriptCode script,
  109.                 WEHandle hWE)
  110. {
  111. #pragma unused(hWE)
  112.     return CharacterType(pText, textOffset, script);
  113. } // _WEStdCharType
  114.  
  115. pascal short _WEScriptToFont(ScriptCode script)
  116. {
  117.     // given an explicit script code, return the first font ID in the corresponding range
  118.     // for an explanation of the formula given below, see IM: Text, page B-8
  119.  
  120.     if (script == smRoman)
  121.         return 2;
  122.     else if ((script > smRoman) && (script <= smUninterp))
  123.         return (0x3E00 + 0x200 * script);
  124.     else
  125.         return systemFont;    // unknown script code (?)
  126. } // _WEScriptToFont
  127.  
  128. #if !SystemSevenFiveOrLater
  129.  
  130. pascal void _WEOldWordBreak(Ptr pText, short textLength, short offset,
  131.                 char edge, OffsetTable breakOffsets, ScriptCode script,
  132.                 WEHandle hWE)
  133. {
  134.     GrafPtr savePort, tempPort;
  135.     short saveFont;
  136.  
  137.     // the old (now obsolete) FindWord routine gets an implicit script parameter through
  138.     // the current graphics port txFont field, so first of all we must have a valid port
  139.     GetPort(&savePort);
  140.     tempPort = (*hWE)->port;
  141.     SetPort(tempPort);
  142.  
  143.     // then set the txFont field to a font number in the specified script range
  144.     saveFont = tempPort->txFont;
  145.     TextFont(_WEScriptToFont(script));
  146.  
  147.     // call _FindWord
  148.     FindWord(pText, textLength, offset, (Boolean)edge, NULL, breakOffsets);
  149.  
  150.     // restore font and port
  151.     TextFont(saveFont);
  152.     SetPort(savePort);
  153.  
  154. } // _WEOldWordBreak
  155.  
  156. pascal short _WEOldCharByte(Ptr pText, short textOffset, ScriptCode script,
  157.                 WEHandle hWE)
  158. {
  159.     GrafPtr savePort, tempPort;
  160.     short saveFont;
  161.     short retVal;
  162.  
  163.     // the old (now obsolete) CharByte routine gets an implicit script parameter through
  164.     // the current graphics port txFont field, so first of all we must have a valid port
  165.     GetPort(&savePort);
  166.     tempPort = (*hWE)->port;
  167.     SetPort(tempPort);
  168.  
  169.     // then set the txFont field to a font number in the specified script range
  170.     saveFont = tempPort->txFont;
  171.     TextFont(_WEScriptToFont(script));
  172.  
  173.     // call _CharByte
  174.     retVal = CharByte(pText, textOffset);
  175.  
  176.     // restore font and port
  177.     TextFont(saveFont);
  178.     SetPort(savePort);
  179.  
  180.     return retVal;
  181. } // _WEOldCharByte
  182.  
  183. pascal short _WEOldCharType(Ptr pText, short textOffset, ScriptCode script,
  184.                 WEHandle hWE)
  185. {
  186.     GrafPtr savePort, tempPort;
  187.     short saveFont;
  188.     short retVal;
  189.  
  190.     // the old (now obsolete) CharType routine gets an implicit script parameter through
  191.     // the current graphics port txFont field, so first of all we must have a valid port
  192.     GetPort(&savePort);
  193.     tempPort = (*hWE)->port;
  194.     SetPort(tempPort);
  195.  
  196.     // then set the txFont field to a font number in the specified script range
  197.     saveFont = tempPort->txFont;
  198.     TextFont(_WEScriptToFont(script));
  199.  
  200.     // call _CharType
  201.     retVal = CharType(pText, textOffset);
  202.  
  203.     // restore font and port
  204.     TextFont(saveFont);
  205.     SetPort(savePort);
  206.  
  207.     return retVal;
  208.  
  209. } // _WEOldCharType
  210.  
  211. #endif
  212.  
  213. pascal OSErr _WERegisterWithTSM(WEHandle hWE)
  214. {
  215.     WEPtr pWE = *hWE;    // assume WE record is already locked
  216.     InterfaceTypeList typeList;
  217.     OSErr err;
  218.  
  219.     // do nothing if the Text Services Manager isn't available
  220.     if (BTST(pWE->flags, weFHasTextServices))
  221.     {
  222.         typeList[0] = kTextService;
  223.         if ((err = NewTSMDocument(1, typeList, &pWE->tsmReference, (long)hWE)) != noErr)
  224.         {
  225.             // we don't consider it an error if our client application isn't TSM-aware
  226.             if (err != tsmNeverRegisteredErr)
  227.             {
  228.                 goto cleanup;
  229.             }
  230.         }
  231.     }
  232.  
  233.     // clear result code
  234.     err = noErr;
  235.  
  236. cleanup:
  237.     // return result code
  238.     return err;
  239. }
  240.  
  241. pascal void _WESetStandardHooks(WEHandle hWE)
  242. {
  243.     WEPtr pWE;
  244.  
  245.     // the first time we're called, create routine descriptors
  246.     if (_weStdDrawTextProc == NULL)
  247.     {
  248.         _weStdDrawTextProc = NewWEDrawTextProc(_WEStdDrawText);
  249.         _weStdPixelToCharProc = NewWEPixelToCharProc(_WEStdPixelToChar);
  250.         _weStdCharToPixelProc = NewWECharToPixelProc(_WEStdCharToPixel);
  251.         _weStdLineBreakProc = NewWELineBreakProc(_WEStdLineBreak);
  252.  
  253. #if !SystemSevenFiveOrLater
  254.  
  255.         if (GetScriptManagerVariable(smVersion) < 0x0710)
  256.         {
  257.             // pre-7.1 version of the Script Manager: must use old hooks
  258.             _weStdWordBreakProc = NewWEWordBreakProc(_WEOldWordBreak);
  259.             _weStdCharByteProc = NewWECharByteProc(_WEOldCharByte);
  260.             _weStdCharTypeProc = NewWECharTypeProc(_WEOldCharType);
  261.         }
  262.         else
  263. #endif
  264.         {
  265.             // Script Manager version 7.1 or newer
  266.             _weStdWordBreakProc = NewWEWordBreakProc(_WEStdWordBreak);
  267.             _weStdCharByteProc = NewWECharByteProc(_WEStdCharByte);
  268.             _weStdCharTypeProc = NewWECharTypeProc(_WEStdCharType);
  269.         }
  270.     } // if called for the first time
  271.  
  272.     // replace null hook fields with the addresses of the standard hooks
  273.  
  274.     pWE = *hWE;
  275.  
  276.     // replace null hook fields with the addresses of the standard hooks
  277.  
  278.     if (pWE->drawTextHook == NULL)
  279.         pWE->drawTextHook = _weStdDrawTextProc;
  280.  
  281.     if (pWE->pixelToCharHook== NULL)
  282.         pWE->pixelToCharHook = _weStdPixelToCharProc;
  283.  
  284.     if (pWE->charToPixelHook== NULL)
  285.         pWE->charToPixelHook = _weStdCharToPixelProc;
  286.  
  287.     if (pWE->lineBreakHook== NULL)
  288.         pWE->lineBreakHook = _weStdLineBreakProc;
  289.  
  290.     if (pWE->wordBreakHook== NULL)
  291.         pWE->wordBreakHook = _weStdWordBreakProc;
  292.     
  293.     if (pWE->charByteHook== NULL)
  294.         pWE->charByteHook = _weStdCharByteProc;
  295.  
  296.     if (pWE->charTypeHook== NULL)
  297.         pWE->charTypeHook = _weStdCharTypeProc;
  298.  
  299. } // _WESetStandardHooks
  300.  
  301. pascal OSErr WENew(const LongRect *destRect, const LongRect *viewRect, short features, WEHandle *hWE)
  302. {
  303.     WEPtr pWE = NULL;
  304.     short allocFlags = kAllocClear;
  305.     long response;
  306.     Rect r;
  307.     OSErr err;
  308.  
  309.     // allocate the WE record
  310.     if ((err = _WEAllocate(sizeof(WERec), allocFlags, (Handle *)hWE)) != noErr) 
  311.     {
  312.         goto cleanup;
  313.     }
  314.     
  315.     // lock it down
  316.     HLock((Handle)*hWE);
  317.     pWE = **hWE;
  318.  
  319.     // get active port
  320.     GetPort(&pWE->port);
  321.  
  322.     // determine whether temporary memory should be used for data structures
  323.     if (BTST(features, weFUseTempMem))
  324.     { 
  325.         allocFlags += kAllocTemp;
  326.     }
  327.     
  328.     // allocate the text handle (initially empty)
  329.     if ((err = _WEAllocate(0, allocFlags, (Handle *)&pWE->hText)) != noErr) 
  330.     {
  331.         goto cleanup;
  332.     }
  333.  
  334.     // allocate the line array
  335.     if ((err = _WEAllocate(2 * sizeof(LineRec), allocFlags, (Handle *)&pWE->hLines)) != noErr) 
  336.     {
  337.         goto cleanup;
  338.     }
  339.  
  340.     // allocate the style table
  341.     if ((err = _WEAllocate(sizeof(StyleTableElement), allocFlags, (Handle *)&pWE->hStyles)) != noErr) 
  342.     {
  343.         goto cleanup;
  344.     }
  345.     
  346.     // allocate the run array
  347.     if ((err = _WEAllocate(2 * sizeof(RunArrayElement), allocFlags, (Handle *)&pWE->hRuns)) != noErr) 
  348.     {
  349.         goto cleanup;
  350.     }
  351.     
  352.     // check for the presence of various system software features
  353.     // determine whether Color QuickDraw is available
  354.     if ((Gestalt(gestaltQuickdrawVersion, &response) == noErr) && (response >= gestalt8BitQD))
  355.     {
  356.         BSET(pWE->flags, weFHasColorQD);
  357.     }
  358.     
  359.     // determine whether the Drag Manager is available
  360.     if ((Gestalt(gestaltDragMgrAttr, &response) == noErr) && BTST(response, gestaltDragMgrPresent))
  361.     {
  362. #if GENERATINGCFM
  363.         if ((unsigned long) NewDrag != kUnresolvedCFragSymbolAddress)
  364. #endif
  365.             BSET(pWE->flags, weFHasDragManager);
  366.     }
  367.  
  368.     // determine whether the Text Services manager is available
  369.     if (Gestalt(gestaltTSMgrVersion, &response) == noErr)
  370.     { 
  371.         BSET(pWE->flags, weFHasTextServices);
  372.     }
  373.     
  374.     // determine if there are any non-Roman scripts enabled
  375.     if (GetScriptManagerVariable(smEnabled) > 1) 
  376.     {
  377.         BSET(pWE->flags, weFNonRoman);
  378.         
  379.         // determine whether a double-byte script is installed
  380.         if (GetScriptManagerVariable(smDoubleByte) != 0)
  381.         {
  382. #if GENERATING68K
  383.             BSET(pWE->flags, weFDoubleByte);    // the WorldScript Power Adapter breaks this :-(
  384. #else
  385.             ScriptCode script;
  386.             for ( script = smRoman; script <= smKlingon; script++ )
  387.             {
  388.                 if (GetScriptVariable(script, smEnabled) &&
  389.                     ((GetScriptVariable(script, smScriptFlags) & smsfSingByte) == 0))
  390.                 {
  391.                     BSET(pWE->flags, weFDoubleByte);
  392.                     break;
  393.                 }
  394.             }
  395. #endif
  396.         }
  397.         
  398.         // determine whether a bidirectional script is installed
  399.         if (GetScriptManagerVariable(smBidirect) != 0)
  400.         {
  401.             BSET(pWE->flags, weFBidirectional);
  402.             
  403.             // should we use a dual caret?
  404.             if ((GetScriptManagerVariable(smGenFlags) & smfDualCaret) != 0)
  405.             {
  406.                 BSET(pWE->flags, weFUseDualCaret);
  407.             }
  408.         }
  409.     }
  410.     
  411.     // initialize miscellaneous fields of the WE record
  412.     pWE->nLines = 1;
  413.     pWE->nStyles = 1;
  414.     pWE->nRuns = 1;
  415.     pWE->viewRect = *viewRect;
  416.     pWE->destRect = *destRect;
  417.     pWE->features = features;
  418.     pWE->tsmAreaStart = kInvalidOffset;
  419.     pWE->tsmAreaEnd = kInvalidOffset;
  420.     pWE->dragCaretOffset = kInvalidOffset;
  421.  
  422.     // initialize hook fields with the addresses of the standard hooks
  423.     _WESetStandardHooks(*hWE);
  424.  
  425.     // create a region to hold the view rectangle
  426.     pWE->viewRgn = NewRgn();
  427.     WELongRectToRect(viewRect, &r);
  428.     RectRgn(pWE->viewRgn, &r);
  429.  
  430.     // initialize the style run array
  431.     (*pWE->hRuns)[1].runStart = 1;
  432.     (*pWE->hRuns)[1].styleIndex = -1;
  433.  
  434.     // initialize the style table
  435.     (*pWE->hStyles)[0].refCount = 1;
  436.  
  437.     // copy text attributes from the active graphics port
  438.     (*pWE->hStyles)[0].info.runStyle.tsFont = pWE->port->txFont;
  439.     (*pWE->hStyles)[0].info.runStyle.tsSize = pWE->port->txSize;
  440.     (*pWE->hStyles)[0].info.runStyle.tsFace = pWE->port->txFace;
  441.     if (BTST(pWE->flags, weFHasColorQD))
  442.     { 
  443.         GetForeColor(&(*pWE->hStyles)[0].info.runStyle.tsColor);
  444.     }
  445.     _WEFillFontInfo(pWE->port, &(*pWE->hStyles)[0].info);
  446.  
  447.     // initialize the line array
  448.     if ((err = WECalText(*hWE)) != noErr) 
  449.     {
  450.         goto cleanup;
  451.     }
  452.     
  453.     // register with the Text Services Manager
  454.     if ((err = _WERegisterWithTSM(*hWE)) != noErr) 
  455.     {
  456.         goto cleanup;
  457.     }
  458.  
  459.     // unlock the WE record
  460.     HUnlock((Handle)*hWE);
  461.  
  462.     // skip clean-up section
  463.     return noErr;
  464.  
  465. cleanup:
  466.     // clean up
  467.     if (pWE != NULL) 
  468.     {
  469.         _WEForgetHandle((Handle *)&pWE->hText);
  470.         _WEForgetHandle((Handle *)&pWE->hLines);
  471.         _WEForgetHandle((Handle *)&pWE->hStyles);
  472.         _WEForgetHandle((Handle *)&pWE->hRuns);
  473.         if (pWE->viewRgn != NULL) 
  474.         {
  475.             DisposeRgn(pWE->viewRgn);
  476.         }
  477.     }
  478.     _WEForgetHandle((Handle *)hWE);
  479.  
  480.     return err;
  481. }
  482.  
  483. pascal void WEDispose(WEHandle hWE)
  484. {
  485.     WEPtr pWE;
  486.  
  487.     // sanity check: make sure WE isn't NULL
  488.     if (hWE == NULL)
  489.         return;
  490.  
  491.     // lock the WE record
  492.     HLock((Handle) hWE);
  493.     pWE = *hWE;
  494.  
  495.     // clear the Undo buffer
  496.     WEClearUndo(hWE);
  497.  
  498.     // unregister with the Text Services Manager
  499.     if (pWE->tsmReference != NULL)
  500.     {
  501.         DeleteTSMDocument(pWE->tsmReference);            
  502.         pWE->tsmReference = NULL;
  503.     }
  504.  
  505.     // dispose of the offscreen graphics world
  506.     if (pWE->offscreenPort != NULL) 
  507.     {
  508.         DisposeGWorld((GWorldPtr)pWE->offscreenPort);
  509.         pWE->offscreenPort = NULL;
  510.     }
  511.  
  512. #if WASTE_OBJECTS
  513.     // dispose all embedded objects
  514.     if (pWE->hStyles != NULL)
  515.     {
  516.         StyleTablePtr pTable;
  517.         long index;
  518.  
  519.         // lock the style table
  520.         HLock((Handle) pWE->hStyles);
  521.         pTable = *pWE->hStyles;
  522.  
  523.         // walk the style table, disposing of all embedded objects referenced there
  524.         for ( index = 0; index < pWE->nStyles; index++ )
  525.         {
  526.             if ((pTable->refCount > 0) && (pTable->info.runStyle.tsObject != NULL))
  527.                 _WEFreeObject(pTable->info.runStyle.tsObject);
  528.             pTable++;
  529.         };
  530.     }
  531.  
  532.     // dispose instance-specific object handler table
  533.     _WEForgetHandle((Handle *) &pWE->hObjectHandlerTable);
  534. #endif
  535.     
  536.     // dispose of auxiliary data structures
  537.     _WEForgetHandle((Handle *) &pWE->hText);
  538.     _WEForgetHandle((Handle *) &pWE->hLines);
  539.     _WEForgetHandle((Handle *) &pWE->hStyles);
  540.     _WEForgetHandle((Handle *) &pWE->hRuns);
  541.     DisposeRgn(pWE->viewRgn);
  542.  
  543.     // dispose of the WE record
  544.     DisposeHandle((Handle) hWE);
  545. }
  546.  
  547. pascal short WEFeatureFlag(short feature, short action, WEHandle hWE)
  548. {
  549.     WEPtr pWE = *hWE;
  550.     short status;
  551.  
  552.     // get current status of the specified feature
  553.     status = BTST(pWE->features, feature) ? weBitSet : weBitClear;
  554.  
  555.     // if action is weBitToggle, invert flag
  556.     if (action == weBitToggle)
  557.         action = 1 - status;
  558.  
  559.     // reset flag according to action
  560.     if (action == weBitClear)
  561.     { 
  562.         BCLR(pWE->features, feature);
  563.     }
  564.     else if (action == weBitSet)
  565.     { 
  566.         BSET(pWE->features, feature);
  567.     }
  568.     
  569.     // return old status
  570.     return status;
  571. }
  572.